package org.rency.common.trigger.schedule.repository;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.rency.common.trigger.beans.TaskStatusEnum;
import org.rency.common.trigger.util.TriggerDict;
import org.rency.common.utils.tool.InetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class DaemonTaskTriggerRepositoryImpl extends JdbcDaoSupport implements DaemonTaskTriggerRepository {
	
	private static final Logger logger = LoggerFactory.getLogger(DaemonTaskTriggerRepositoryImpl.class);
	
	private RowMapper<DaemonTaskTriggerDO> rowMapper = new RowMapper<DaemonTaskTriggerDO>() {

		@Override
		public DaemonTaskTriggerDO mapRow(ResultSet rs, int rowNum) throws SQLException {
			DaemonTaskTriggerDO entity = new DaemonTaskTriggerDO();
			entity.setBeanName(rs.getString("bean_name"));
			entity.setConcurrentTag(rs.getString("concurrent_enable"));
			entity.setCreateTime(rs.getTimestamp("create_time"));
			entity.setCronExpression(rs.getString("cron_expression"));
			entity.setDescription(rs.getString("description"));
			entity.setMachineHost(rs.getString("machine_host"));
			entity.setMachineIp(rs.getString("machine_ip"));
			entity.setMemo(rs.getString("memo"));
			entity.setNextFire(rs.getTimestamp("next_fire"));
			entity.setPreviousFire(rs.getTimestamp("previous_fire"));
			entity.setStatus(rs.getString("status"));
			entity.setTriggerId(rs.getInt("trigger_id"));
			entity.setUpdateTime(rs.getTimestamp("update_time"));
			return entity;
		}
		
	};
	
	@Override
	public List<DaemonTaskTriggerDO> loadTriggerByStatus(TaskStatusEnum status) {
		return super.getJdbcTemplate().query(TriggerDict.SQL_LOAD_BY_STATUS,new Object[]{status.getCode()},rowMapper);
	}

	@Override
	public boolean save(DaemonTaskTriggerDO entity) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_INSERT, new Object[]{entity.getBeanName(),entity.getDescription(),entity.getCronExpression(),entity.getPreviousFire(),entity.getNextFire(),entity.getStatus(),entity.getConcurrentTag(),entity.getMachineIp(),entity.getMachineHost(),entity.getMemo(),entity.getCreateTime()}) > 0;
	}

	@Override
	public boolean delete(Integer triggerId) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_DELETE_BY_ID, triggerId) > 0;
	}
	
	@Override
	public boolean delete(String beanName) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_DELETE_BY_BEAN_NAME, beanName) > 0;
	}
	
	@Override
	public boolean updateNextFireById(Integer triggerId, Date nextFire) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_NEXT_FIRE, new Object[]{nextFire,triggerId}) > 0;
	}

	@Override
	public boolean updatePreviousFireById(Integer triggerId, Date previousFire) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_PREVIOUS_FIRE, new Object[]{previousFire,triggerId}) > 0;
	}

	@Override
	public boolean updateStatusById(Integer triggerId, TaskStatusEnum newStatus,TaskStatusEnum oldStatus) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_STATUS_BY_ID, new Object[]{newStatus.getCode(),triggerId,oldStatus.getCode()}) > 0;
	}

	@Override
	public boolean updateFireById(Integer triggerId, Date previousFire, Date nextFire) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_FIRE, new Object[]{previousFire,nextFire,triggerId}) > 0;
	}
	
	@Override
	public boolean updateMachineInfo(Integer triggerId, String hostName, String localAddr) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_MACHINE,new Object[]{localAddr,hostName,triggerId}) > 0;
	}

	@Override
	public DaemonTaskTriggerDO find(Integer triggerId) {
		List<DaemonTaskTriggerDO> list = super.getJdbcTemplate().query(TriggerDict.SQL_FIND_BY_ID,new Object[]{triggerId},rowMapper);
		if(CollectionUtils.isEmpty(list) || list.size() ==0 ){
			return null;
		}
		return list.get(0);
	}
	
	@Override
	public DaemonTaskTriggerDO find(String beanName) {
		List<DaemonTaskTriggerDO> list = super.getJdbcTemplate().query(TriggerDict.SQL_FIND_BY_NAME,new Object[]{beanName},rowMapper);
		if(CollectionUtils.isEmpty(list) || list.size() ==0 ){
			return null;
		}
		return list.get(0);
	}

	@Override
	public boolean updateStatusByName(String beanName, TaskStatusEnum newStatus,TaskStatusEnum oldStatus) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_STATUS_BY_NAME, new Object[]{newStatus.getCode(),beanName,oldStatus.getCode()}) > 0;
	}
	
	@Override
	public List<DaemonTaskTriggerDO> loadAll() {
		return super.getJdbcTemplate().query(TriggerDict.SQL_LOAD_ALL, rowMapper);
	}
	
	@Override
	public boolean updateStatusMachineFire(Integer triggerId, TaskStatusEnum newStatus, TaskStatusEnum oldStatus,
			String hostName, String localAddr, Date previousFire, Date nextFire) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_STATUS_MACHINE_FIRE_BY_ID, new Object[]{newStatus.getCode(),localAddr,hostName,previousFire,nextFire,triggerId,oldStatus.getCode()}) > 0;
	}
	
	@Override
	public boolean updateStatusMachineFire(String beanName, TaskStatusEnum newStatus, TaskStatusEnum oldStatus,
			String hostName, String localAddr, Date previousFire, Date nextFire) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_STATUS_MACHINE_FIRE_BY_NAME, new Object[]{newStatus.getCode(),localAddr,hostName,previousFire,nextFire,beanName,oldStatus.getCode()}) > 0;
	}

	@Override
	public boolean updateCronExpression(String beanName, String cronExpression) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_CRON, new Object[]{cronExpression,beanName}) > 0;
	}

	
	@Override
	public boolean updateStatusBulk(TaskStatusEnum newStatus, TaskStatusEnum oldStatus) {
		return super.getJdbcTemplate().update(TriggerDict.SQL_UPDATE_STATUS_BULK, new Object[]{newStatus.getCode(),oldStatus.getCode()}) > 0;
	}

	@Override
	public boolean initStatus() {
		String localHost = InetUtils.getLocalAddr();
		String localHostName = InetUtils.getLocalHost();
		List<DaemonTaskTriggerDO> list = super.getJdbcTemplate().query(TriggerDict.SQL_LOAD_BY_MACHINE, rowMapper,new Object[]{localHost});
		if(CollectionUtils.isEmpty(list)){
			return true;
		}
		for(DaemonTaskTriggerDO entity : list){
			if(TaskStatusEnum.NORMAL != TaskStatusEnum.get(entity.getStatus())){
				this.updateStatusById(entity.getTriggerId(), TaskStatusEnum.NORMAL, TaskStatusEnum.get(entity.getStatus()));
				this.updateMachineInfo(entity.getTriggerId(), localHostName, localHost);
			}
		}
		return true;
	}

	
	@Override
	public void createTable() {
		logger.info("执行定时任务脚本...");
		try {
			DatabaseMetaData metaData = super.getDataSource().getConnection().getMetaData();
			if(isExists(TriggerDict.SQL_TABLE_NAME,metaData)){
				return;
			}
			super.getJdbcTemplate().execute(TriggerDict.SQL_CREATE_TABLE);
			super.getJdbcTemplate().execute(TriggerDict.SQL_CREATE_UNIQUE_INDEX);
		} catch (SQLException e) {
			logger.error("执行定时任务脚本发生异常,{}.",TriggerDict.SQL_CREATE_TABLE,e);
		}
		logger.info("执行定时任务脚本完成...");
	}
	
	/**
	 * 判断数据表是否存在
	 * </br>Created on 2016年4月15日
	 * @param tableName
	 * @param metaData
	 * @return
	 * @throws SQLException
	 */
	private boolean isExists(String tableName,DatabaseMetaData metaData) throws SQLException{
		ResultSet rs = null;
		try {
			rs = metaData.getTables(null, null, tableName, new String[]{"TABLE"});
			if(rs.next()){
				return true;
			}
		} catch (SQLException e) {
			logger.error("判断数据表是否存在异常,表名:{}.",tableName,e);
		}finally{
			if(rs != null){
				try {
					rs.close();
				} catch (SQLException e) {
				}
			}
		}
		return false;
	}

}
